// 把所有代码放在 自调用函数 内, 为了不让任何变量污染全局
(function(window) {

  // 准备功能函数
  // 专门用来给元素批量设置样式
  function setStyle(ele, styles) {
    for (let k in styles) {
      ele.style[k] = styles[k]
    }
  }

  // 准备一个构造函数
  const Pagination = (function() {
    class Pagination {
      constructor(selector, options = {}) {
        this.selector = selector
        this.options = options
        // 1. 范围元素
        this.ele = document.querySelector(selector)
        // 2. 准备一个自己的配置项
        this.options = {}
        // 3. 保留回调函数
        this.change = options.change || function() {}
        // 4. 直接调用启动器函数
        // 调用的是原型上的 init 方法, 实参就传递给了 init 方法
        // this.init(options)
        this.setParams(options)
        this.setHtml()
      }
  
      // 在原型上书写方法
      // 0. 启动器函数
      init (options) {
        // options 接收用户传递进来的 options
        // 去依次调用各种方法
        this.setParams(options)
        // this.setHtml()
        this.setListBtn()
        this.changeHtml()
        this.bindEvent()
      }
  
      // 1. 调整参数设置默认值
      setParams (options) {
        // options 是用户传递进来的 options
        // 根据用户的 option 来制作我们自己的 options
        // 1-1. 准备好一套默认值(当做用户什么都没有传递, 需要使用的内容)
        this.options = {
          // 文本相关
          text: { first: '首页', prev: '上一页', list: '', next: '下一页', last: '尾页', go: '跳转', ...options.text},
          // 分页器相关
          pagi: { current: 1, pagesize: 12, total: 100, totalPage: 9, ...options.pagi },
          styles: { btnColor: 'skyblue', btnDisableColor: '#ccc', boxWidth: 1200, ...options.styles }
        }
        // 计算一下 totalPage
        // 当用户传递了 totalPage, 那么就不计算了, 如果没传递, 那么计算一下
        if (options.pagi && !options.pagi.totalPage) this.options.totalPage = Math.ceil(this.options.pagi.total / this.options.pagi.pageSize)
      }
  
      // 2. 生成基础结构
      setHtml() {
        // 2-1. 先设置好外部盒子的样式
        setStyle(this.ele, {
          width: this.options.styles.boxWidth + 'px',
          height: '50px',
          border: '1px solid #333',
          margin: '30px auto',
          display: 'flex',
          'align-items': 'center',
          'justify-content': 'space-around',
        })
        // 2-2. 创建一个文档碎片元素
        // 返回值是一个文档碎片节点: 可以承载其他节点, 最终一次性把这个文档碎片插入到 this.ele 内
        // 特点: 当你把文档碎片插入到页面的时候, 文档碎片本身是不进入的, 而是把内部保存的所有内容一次性插入
        const frg = document.createDocumentFragment()
        // 2-3-1. 首页按钮, 设置样式
        this.firstEle = document.createElement('div')
        this.firstEle.innerText = this.options.text.first
        setStyle(this.firstEle, {
          margin: 0,
          padding: '5px 10px',
          'background-color': this.options.styles.btnColor,
          cursor: 'pointer',
          color: '#fff',
        })
        frg.appendChild(this.firstEle)
        // 2-3-2. 上一页按钮
        this.prevEle = this.firstEle.cloneNode()
        this.prevEle.innerText = this.options.text.prev
        frg.appendChild(this.prevEle)
        // 2-3-3. 添加一个 按钮列表元素
        this.listEle = document.createElement('div')
        setStyle(this.listEle, { display: 'flex', margin: 0, padding: 0 })
        frg.appendChild(this.listEle)
        // 2-3-4. 添加一个 下一页按钮
        this.nextEle = this.firstEle.cloneNode()
        this.nextEle.innerText = this.options.text.next
        frg.appendChild(this.nextEle)
        // 2-3-5. 添加一个 尾页按钮
        this.lastEle = this.firstEle.cloneNode()
        this.lastEle.innerText = this.options.text.last
        frg.appendChild(this.lastEle)
        // 2-3-6. 添加一个 文本框 元素
        this.inpEle = document.createElement('input')
        this.inpEle.value = this.options.pagi.current
        setStyle(this.inpEle, {
          width: '60px',
          'text-align': 'center',
          'font-size': '22px',
          height: '30px',
          outline: 'none',
          margin: 0,
          padding: 0
        })
        frg.appendChild(this.inpEle)
        // 2-3-7. 添加一个 跳转按钮 元素
        this.goBtn = document.createElement('button')
        this.goBtn.innerText = this.options.text.go
        setStyle(this.goBtn, {
          height: '30px',
          outline: 'none',
          padding: '0 15px',
          magin: 0,
          cursor: 'pointer'
        })
        frg.appendChild(this.goBtn)
  
        // 最后把框里的内容一次性放在 this.ele 内
        this.ele.appendChild(frg)
      }
  
      // 3. 根据分页信息把 list 标签内的每一个分页按钮渲染
      setListBtn() {
        // 主要是向 this.listEle 内添加 p 标签
        // 根据一共多少页和当前是第几页来决定
        // 拿到信息
        const { pagi : { current, totalPage } } = this.options
        // 生成一个基础 p 标签
        const p = document.createElement('p')
        setStyle(p, {
          padding: '5px',
          border: '1px solid #333',
          margin: '0 5px',
          cursor: 'pointer'
        })
        // 生成一个基础 span 标签
        const span = document.createElement('span')
        span.innerText = '...'
  
        // 准备一个筐
        const frg = document.createDocumentFragment()
  
        // 如果总页数不够 9 页, 那么有多少, 生成多少
        if (totalPage <= 9) {
          for (let i = 1; i <= totalPage; i++) {

            const ele = p.cloneNode()
            if (current === i) setStyle(ele, { backgroundColor: 'orange' })
            ele.innerText = i
            frg.appendChild(ele)
          }
          // 把 frg 插入到 this.listEle 内
          this.listEle.appendChild(frg)
          return
        }
  
        // 代码来到这里, 表示总页数足够 9 页
        if (current < 5 && totalPage > 9) {
          for (let i = 1; i <= 5; i++) {
            const ele = p.cloneNode()
            if (current === i) setStyle(ele, { backgroundColor: 'orange' })
            ele.innerText = i
            frg.appendChild(ele)
          }
          frg.appendChild(span.cloneNode(true))
          for (let i = totalPage - 1; i <= totalPage; i++) {
            const ele = p.cloneNode()
            ele.innerText = i
            frg.appendChild(ele)
          }
          this.listEle.appendChild(frg)
          return
        }
  
        // 当前页等于第 5 页
        if(current === 5 && totalPage > 9) {
          for (let i = 1; i <= 7; i++) {
            const ele = p.cloneNode()
            if (i === 5) setStyle(ele, { backgroundColor: 'orange' })
            ele.innerText = i
            frg.appendChild(ele)
          }
          frg.appendChild(span.cloneNode(true))
          for (let i = totalPage - 1; i <= totalPage; i++) {
            const ele = p.cloneNode()
            ele.innerText = i
            frg.appendChild(ele)
          }
          this.listEle.appendChild(frg)
          return
        }
  
        // 当前页等于倒数第 5 页
        if (current === totalPage - 4 && totalPage > 9) {
          // 生成七个标签
          for (let i = 1; i <= 2; i++) {
            const ele = p.cloneNode()
            ele.innerText = i
            frg.appendChild(ele)
          }
          frg.appendChild(span.cloneNode(true))
          for (let i = totalPage - 6; i <= totalPage; i++) {
            const ele = p.cloneNode()
            if (current === i) setStyle(ele, { backgroundColor: 'orange' })
            ele.innerText = i
            frg.appendChild(ele)
          }
          this.listEle.appendChild(frg)
          return
        }
  
        // 当前大于第 5 页
        if (current > totalPage - 4 && totalPage > 9) {
          for (let i = 1; i <= 2; i++) {
            const ele = p.cloneNode()
            ele.innerText = i
            frg.appendChild(ele)
          }
          frg.appendChild(span.cloneNode(true))
          for (let i = totalPage - 4; i <= totalPage; i++) {
            const ele = p.cloneNode()
            if (current === i) setStyle(ele, { backgroundColor: 'orange' })
            ele.innerText = i
            frg.appendChild(ele)
          }
          this.listEle.appendChild(frg)
          return
        }
  
        // 代码来到这里, 说明当前页在中间
        else {
          for (let i = 1; i <= 2; i++) {
            const ele = p.cloneNode()
            ele.innerText = i
            frg.appendChild(ele)
          }
          frg.appendChild(span.cloneNode(true))
          for (let i = current - 2; i <= current + 2; i++) {
            const ele = p.cloneNode()
            if (current === i) setStyle(ele, { backgroundColor: 'orange' })
            ele.innerText = i
            frg.appendChild(ele)
          }
          frg.appendChild(span.cloneNode(true))
          for (let i = totalPage - 1; i <= totalPage; i++) {
            const ele = p.cloneNode()
            ele.innerText = i
            frg.appendChild(ele)
          }
          this.listEle.appendChild(frg)
        }
        }
  
      // 4. 根据分页信息调整样式
      changeHtml() {
        // 根据当前页决定 首页和上一页 是否禁用
        // 根据当前页决定 尾页和下一页 是否禁用
        const { pagi: { current, totalPage }, styles: { btnDisableColor, btnColor } } = this.options
        if (current <= 1) {
          setStyle(this.firstEle, { backgroundColor: btnDisableColor, cursor: 'not-allowed' })
          setStyle(this.prevEle, { backgroundColor: btnDisableColor, cursor: 'not-allowed' })
        } else {
          setStyle(this.firstEle, { backgroundColor: btnColor, cursor: 'pointer' })
          setStyle(this.prevEle, { backgroundColor: btnColor, cursor: 'pointer' })
        }
  
        if (current >= totalPage) {
          setStyle(this.lastEle, { backgroundColor: btnDisableColor, cursor: 'not-allowed' })
          setStyle(this.nextEle, { backgroundColor: btnDisableColor, cursor: 'not-allowed' })
        } else {
          setStyle(this.lastEle, { backgroundColor: btnColor, cursor: 'pointer' })
          setStyle(this.nextEle, { backgroundColor: btnColor, cursor: 'pointer' })
        }
  
        // 根据当前页调整 文本框 内的 value
        this.inpEle.value = current
  
        // 根据当前页从新调整 this.listEle 内的 标签结构
        this.listEle.innerHTML = ''
        this.setListBtn()
      }
  
      // 5. 给各个元素绑定事件
      bindEvent()  {
        // 首页绑定事件
        this.firstEle.addEventListener('click', () => {
          if (this.options.pagi.current <= 1) return
          this.options.pagi.current = 1
          this.changeHtml()
          this.change(this.options.pagi.current)
        })
        // 上一页绑定事件
        this.prevEle.addEventListener('click', () => {
          if (this.options.pagi.current <= 1) return
          this.options.pagi.current--
          this.changeHtml()
          this.change(this.options.pagi.current)
        })
        // 下一页绑定事件
        this.nextEle.addEventListener('click', () => {
          if (this.options.pagi.current >= this.options.pagi.totalPage) return
          this.options.pagi.current++
          this.changeHtml()
          this.change(this.options.pagi.current)
        })
        // 尾页绑定事件
        this.lastEle.addEventListener('click', () => {
          if (this.options.pagi.current >= this.options.pagi.totalPage) return
          this.options.pagi.current = this.options.pagi.totalPage
          this.changeHtml()
          this.change(this.options.pagi.current)
        })
        // 跳转按钮绑定事件
        this.goBtn.addEventListener('click', () => {
          let page = parseInt(this.inpEle.value.trim())
          if (isNaN(page)) page = 1
          if (page < 1) page = 1
          if (page >= this.options.pagi.totalPage) page = this.options.pagi.totalPage
          this.options.pagi.current = page
          this.changeHtml()
          this.change(this.options.pagi.current)
        })
        // 每一页的点击事件
        this.listEle.addEventListener('click', e => {
          if (e.target.nodeName !== 'P') return
          // 拿到当前标签内的文本
          const page = e.target.innerText - 0
          if (page === this.options.pagi.current) return
          this.options.pagi.current = page
          this.changeHtml()
          this.change(this.options.pagi.current)
        })
      }
    }
    let instance = null
    return function(selector, options) {
      if (!instance) instance = new Pagination(selector, options)
      instance.init(options)
    }
  })()
  
  // 把构造函数挂载到全局
  window.Pagination = Pagination

})(window)